import datetime
import os
import time
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
import traceback
from getcwd import get_cwd
from outputs.Logs.log import get_log


class BasePage(object):
    def __init__(self, driver=None):
        self.driver = driver
        self.log = get_log('Po_project')

    # 等待元素可见
    def __wait_element_visible(self, locator, times=10, poll_frequency=0.5, path=''):
        """
        :param locator: 元素定位
        :param times: 等待最长时间
        :param poll_frequency: 查询间隔
        :param path: 等待元素的路径 百度首页_搜索功能_搜索按钮
        :return:
        """
        try:
            start_time = datetime.datetime.now()
            WebDriverWait(self.driver, times, poll_frequency).until(EC.visibility_of_element_located(locator))
            end_time = datetime.datetime.now()
            self.log.info("{}等待元素{} ,耗时{}秒".format(path, locator, (end_time - start_time).seconds))
        except:
            self.log.exception("{}等待元素{}不可见".format(path, locator))
            self.__get_ScreenShot(path)

    # 等待元素存在
    def wait_element_presence(self, locator, times=10, poll_frequency=0.5, path=''):
        self.log.info("{} 等待元素 {} 存在".format(path, locator))
        try:
            startTime = datetime.datetime.now()
            WebDriverWait(self.driver, times, poll_frequency).until(EC.presence_of_element_located(locator))
            endTime = datetime.datetime.now()
            self.log.info("{} 元素 {}等待结束，等待时长为：{} 秒".format(path, locator, (endTime - startTime).seconds))
            return True
        except:
            self.log.exception("{} 等待元素 {} 存在失败".format(path, locator))
            self.__get_ScreenShot(path)
            return False

    # 查找元素
    def __get_element(self, locator, path=''):
        self.__wait_element_visible(locator=locator, path=path)
        try:
            ele = self.driver.find_element(*locator)
            self.log.info("{} 元素{}查找成功".format(path, locator))
            return ele
        except:
            self.log.exception("{} 元素{}查找失败".format(path, locator))
            self.__get_ScreenShot(path)

    # 切换iframe
    def switch_to_iframe(self, locator, type='id', path=''):
        if type in ['id', 'name', 'index']:
            self.driver.switch_to.frame(locator)
        elif type == 'tag':
            frame = self.driver.find_elements_by_tag_name('iframe')[locator]
            self.driver.switch_to.frame(frame)
        else:
            self.log.exception("切换iframe失败，{}".format(path))

    #  从iframe切回主页面
    def switch_to_page(self):
        self.driver.switch_to.default_content()

    #  下滑到指定元素的位置
    def scroll_to_element(self, locator, path=''):

        # 找到需要下滑位置的元素
        ele = self.__get_element(locator=locator, path=path)

        # 开始滑动
        try:
            self.driver.execute_script("arguments[0].scrollIntoView();", ele)
            self.log.info("{} 下滑到指定元素{} 成功".format(path, locator))
        except:
            self.log.exception("{} 下滑到指定元素{} 失败".format(path, locator))
            self.__get_ScreenShot(path)

    #  鼠标右键操作
    def action_chains_right_click(self, locator, path=''):

        # 找到需要右键的元素
        ele = self.__get_element(locator=locator, path=path)

        # 右键操作
        try:
            ActionChains(self.driver).context_click(ele).perform()
            self.log.info("{} 鼠标右键元素{} 成功".format(path, locator))
        except:
            self.log.exception("{} 鼠标右键元素{} 失败".format(path, locator))
            self.__get_ScreenShot(path)

    #  鼠标双击操作
    def action_chains_double_click(self, locator, path=''):

        # 找到需要双击的元素
        ele = self.__get_element(locator=locator, path=path)

        # 鼠标双击操作
        try:
            ActionChains(self.driver).double_click(ele).perform()
            self.log.info("{} 鼠标双击元素{} 成功".format(path, locator))
        except:
            self.log.exception("{} 鼠标双击元素{} 失败".format(path, locator))
            self.__get_ScreenShot(path)

    #  鼠标悬停操作
    def action_chains_move_element(self, locator, path=''):

        # 找到需要悬停的元素
        ele = self.__get_element(locator=locator, path=path)

        # 鼠标悬停操作
        try:
            ActionChains(self.driver).move_to_element(ele).perform()
            self.log.info("{} 鼠标悬停元素{} 成功".format(path, locator))
        except:
            self.log.exception("{} 鼠标悬停元素{} 失败".format(path, locator))
            self.__get_ScreenShot(path)

    #  鼠标拖动操作
    def action_chains_drag_element(self, source, target, path=''):

        # 找到需要拖动的元素
        source_ele = self.__get_element(locator=source, path=path)

        # 拖动到目录位置元素
        target_ele = self.__get_element(locator=target, path=path)

        # 鼠标执行拖动操作
        try:
            ActionChains(self.driver).drag_and_drop(source_ele, target_ele).perform()
            self.log.info("{} 鼠标拖动元素{} 成功".format(path, source))
        except:
            self.log.exception("{} 鼠标拖动元素{} 失败".format(path, source))
            self.__get_ScreenShot(path)

    # Alert弹窗处理
    def alert_deal(self, type='accept', path=''):
        """
        :param type: 默认值 accept，确定操作、dismiss 取消操作、text 获取alert框上的文本
        :param path: 操作页面
        :return: target.text 返回alert弹框文本
        """
        try:
            target = self.driver.switch_to.alert
            if type.lower() == 'accept':
                target.accept()
                self.log.info("{} alert 弹框 {} 成功。".format(path, type))
            elif type.lower() == 'dismiss':
                target.dismiss()
                self.log.info("{} alert 弹框 {} 成功。".format(path, type))
            elif type.lower() == 'text':
                self.log.info("{} alert 弹框 {} 文本获取成功。".format(path, type))
                return target.text
            else:
                self.log.exception("{} alert 不存在 {} 方法。".format(path, type))
        except:
            self.log.exception("{} alert {} 失败".format(path, type))
            self.__get_ScreenShot(path)

    # 点击元素
    def click_element(self, locator, path=''):
        # 第一步 查找元素
        el = self.__get_element(locator=locator, path=path)
        try:
            el.click()
            self.log.info("{} 元素{}点击成功".format(path, locator))
        except:
            self.log.exception("{} 元素{}点击失败".format(path, locator))
            self.__get_ScreenShot(path)

    # 查找元素并输入
    def input_text(self, locator, text, path=''):
        # 第一步 查找元素
        el = self.__get_element(locator=locator, path=path)
        try:
            el.clear()
            el.send_keys(text)
            self.log.info("{} 元素{}输入成功".format(path, locator))
        except:
            self.log.exception("{} 元素{}输入失败".format(path, locator))
            self.__get_ScreenShot(path)

    # 获取元素属性
    def get_attribute(self, locator, attr, path):
        """
        :param locator: 定位
        :param attr: 需要获取属性值的属性
        :param path: 页面路径
        :return: 获取的属性值
        """
        # 获取元素
        ele = self.__get_element(locator=locator, path=path)

        # 获取属性
        try:
            return ele.get_attribute(attr)
        except:
            self.log.exception("{} {} 元素{}属性值获取失败".format(path, locator, attr))
            self.__get_ScreenShot(path)

    # 获取元素文本
    def get_element_text(self, locator, path=''):
        # 找元素
        ele = self.__get_element(locator, path)
        try:
            return ele.text
        except:
            self.log.exception("{} 获取元素 {} 文本失败".format(path, locator))
            self.__get_ScreenShot(path)

    # 切换到指定的窗口，通过窗口标题和URL(标题相同的话，按先后顺序取一个)
    def switch_to_window_handle(self, flag: str, name: str):
        """
        :param flag: 切换指定handle 方式，为：title、url
        :param name: flag为 url时，指目标handle页面的URL，否则为title
        :return: None
        """
        try:
            handles = self.driver.window_handles
            for handle in handles:
                self.driver.switch_to.window(handle)
                if flag.lower() == 'title':
                    page_title = self.driver.title
                    if name in page_title:
                        self.driver.switch_to.window(handle)
                elif flag.lower() == 'url':
                    page_url = self.driver.url
                    if name in page_url:
                        self.driver.switch_to.window(handle)
                else:
                    self.log.exception("切换窗口方式错误。")
        except:
            self.log.exception(traceback.print_exc())

    # 获取浏览器title
    def get_browserTitle(self, path=''):
        try:
            return self.driver.title
        except:
            self.log.exception("{} 标题获取失败".format(path))
            self.__get_ScreenShot(path)

    # 关闭窗口
    def close_window_handle(self, path):
        try:
            self.driver.close()
        except:
            self.log.exception("{} 关闭窗口失败".format(path))
            self.__get_ScreenShot(path)

    # 截图
    def __get_ScreenShot(self, path1=''):
        dirPath = os.path.join(get_cwd(), 'outputs/picture/')
        name = dirPath + path1 + time.strftime('%Y_%h_%m_%H_%M_%S') + '.png'
        try:
            self.driver.get_screenshot_as_file(name)
        except:
            self.log.exception("{}截图失败".format(path1))
